#include<WinSock2.h>
#include <stdio.h>
#include "../Common/Common.h"
#include <windows.h>

TUserInfo* rootUser = NULL;
int myId = -1;
SOCKET sockClient;
SOCKET viceSockClient = INVALID_SOCKET;
int userNum = 0;
HANDLE InvalidViceEvent;

int t, l=sizeof(int);

SOCKET connectAgain(int myId, int userNum) {
	char buffer[MAXBUFFSIZE];
	SOCKET sockClient;

	if (viceSockClient != INVALID_SOCKET) {
		sockClient = viceSockClient;
		viceSockClient = INVALID_SOCKET;
		SetEvent(InvalidViceEvent);
// 		printf("turn to vice boss.\n");

// 		getsockopt(sockClient, SOL_SOCKET, SO_RCVTIMEO, (char*)&t, &l);
// 		printf("recv time out: %d\n", t);
	}
	else
		sockClient = createServerConnectSocket(LOCALHOST);
	
	memset(buffer, 0, MAXBUFFSIZE);
	sprintf(buffer, "%d %d %d#", YES, myId, userNum);
	send(sockClient, buffer, strlen(buffer), 0);

	return sockClient;
}

void closeIn2s(void *args) {
	Sleep(800+userNum);
	exit(0);
}

BOOL closing(DWORD ctrlType) {
	char buffer[MAXBUFFSIZE];
	SOCKET tmpSocket;

	if (ctrlType == CTRL_CLOSE_EVENT || ctrlType == CTRL_C_EVENT) {
		_beginthread(closeIn2s, 0, NULL);
		tmpSocket = createServerConnectSocket(LOCALHOST);
		memset(buffer, 0, MAXBUFFSIZE*sizeof(char));
		sprintf(buffer, "%d %d#", PINODE_QUIT, myId);
		send(tmpSocket, buffer, strlen(buffer), 0);
		closesocket(tmpSocket);
	}
	return TRUE;
}

void findVice(void *args) {
	SOCKET sock;
	char buf[MAXBUFFSIZE];
	DWORD waitRes;

	while (1) {
		sock = createConnectSocket(VICE_PORT, LOCALHOST);
		if (sock != INVALID_SOCKET) {
			sprintf(buf, "%d %d#", PLNODE, myId);
			send(sock, buf, strlen(buf), 0);
			viceSockClient = sock;
// 			printf("find vice boss: %d\n", sock);
			while (1) {
				waitRes = WaitForSingleObject(InvalidViceEvent, 1000);
// 				printf("wait res: %d,      %d, %d\n", waitRes, WAIT_OBJECT_0, WAIT_TIMEOUT);
				if (waitRes == WAIT_OBJECT_0) break;

				if (!testSocket(viceSockClient)) {
					viceSockClient = INVALID_SOCKET;
					break;
				}
			}
		}
		Sleep(500);
	}
}

void main()
{
	char recvBuffer[MAXBUFFSIZE];
	int recvBytes;
	char sendBuffer[MAXBUFFSIZE];
	TOperationInfo op;
	bool b;
	int errorCode;
	int *allUsers = NULL;
	int i;


// 	freopen("debug.txt", "w", stdout);

	SetConsoleCtrlHandler((PHANDLER_ROUTINE)closing, TRUE);

	startUpNetwork();

	sockClient = createServerConnectSocket(LOCALHOST);

	memset(sendBuffer, 0, MAXBUFFSIZE);
	sprintf(sendBuffer, "%d#", NO);
	send(sockClient, sendBuffer, strlen(sendBuffer), 0);

	recv(sockClient, recvBuffer, MAXBUFFSIZE, 0);
	sscanf(recvBuffer, "%d %d", &op.op, &op.val);
	if(op.op == ADD_PINODE_SUCCESS) {
		printf("connect success! my node ID: %d\n", op.val);
		myId = op.val;
	} else {
		fprintf(stderr, "connect fail! will exit.\n");
		system("pause");
		exit(1);
	}

	InvalidViceEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
	_beginthread(findVice, 0, NULL);

	while(1) {
		recvBytes = recv(sockClient, recvBuffer, MAXBUFFSIZE, 0);

		if (recvBytes == -1) {
			errorCode = GetLastError();
// 			printf("recv error: %d\n", errorCode);

			getsockopt(sockClient, SOL_SOCKET, SO_RCVTIMEO, (char*)&t, &l);
// 			printf("recv time out: %d\n", t);

 			if (errorCode != 10060) {//controller down
				//closesocket(sockClient);
				sockClient = connectAgain(myId, userNum);
				continue;
 			}
		}
		recvBuffer[recvBytes] = 0;

// 		printf("recv operation: %s\n", recvBuffer);

		sscanf(recvBuffer, "%d %d", &op.op, &op.val);
		switch(op.op) 
		{
		case CONNECT_REQUEST:
			b = addUser(rootUser, op.val, &rootUser);
			
			if(b == true) {
				sprintf(sendBuffer, "%d %d", YES, 0);
				++userNum;
				printf("user %d CONNECT, node %d has %d users.\n", op.val, myId, userNum);
// 				if (op.val != 10 && userNum == 11) {
// 					system("pause");
// 				}
			} else {
				sprintf(sendBuffer, "%d %d", NO, 0);
			}
			send(sockClient, sendBuffer, strlen(sendBuffer) + 1, 0);
			break;
		case DELETE_REQUEST:

			b = deleteUser(rootUser, op.val, &rootUser);
			
			if(b == true) {
				sprintf(sendBuffer, "%d %d", YES, 0);
				--userNum;
				printf("user %d RELEASE, node %d has %d users.\n", op.val, myId, userNum);
			} else {
				sprintf(sendBuffer, "%d %d", NO, 0);
			}
			send(sockClient, sendBuffer, strlen(sendBuffer) + 1, 0);
			break;
		case GETPNODEBYUSER:
			b = find(rootUser, op.val, &rootUser);
			if(b == true) {
				sprintf(sendBuffer, "%d %d", YES, 0);
			} else {
				sprintf(sendBuffer, "%d %d", NO, 0);
			}
// 			printf("ret back: %s\n", sendBuffer);
			send(sockClient, sendBuffer, strlen(sendBuffer) + 1, 0);
			break;
		case GETUSERNUMBYPNODE:
			sprintf(sendBuffer, "%d %d", YES, userNum);
			send(sockClient, sendBuffer, strlen(sendBuffer)+1, 0);
			break;
		case PINODE_QUIT:
			printf("start sending data...\n");
			if (userNum > 0) {
				allUsers = (int*)malloc(userNum*sizeof(int));
				getAllUsers(rootUser, allUsers);
				for (i=0; i<userNum; ++i) {
					sprintf(sendBuffer, "%d ", allUsers[i]);
					errorCode = send(sockClient, sendBuffer, strlen(sendBuffer), 0);
					if (errorCode < 0) break;
				}
				free(allUsers);
				if (errorCode < 0) break;
			}
			sprintf(sendBuffer, "#");
			errorCode = send(sockClient, sendBuffer, strlen(sendBuffer), 0);
			if (errorCode < 0) break;
			printf("waiting end\n");
			errorCode = recv(sockClient, sendBuffer, MAXBUFFSIZE, 0);
			if (errorCode < 0) break;
			exit(0);
			break;
		default:
			printf("op error from Controller! %s\n", recvBuffer);
			break;
		}	
	}
}
